package com.shun.gateway.config;

import cn.dev33.satoken.reactor.filter.SaReactorFilter;
import cn.dev33.satoken.router.SaRouter;
import cn.dev33.satoken.stp.StpUtil;
import com.shun.common.R;
import com.shun.gateway.handler.ShunWebFluxErrorHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.ServerProperties;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.reactive.CorsWebFilter;
import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
import org.springframework.web.reactive.result.view.ViewResolver;
import org.springframework.web.util.pattern.PathPatternParser;

import java.util.stream.Collectors;

@Slf4j
@Configuration
@EnableConfigurationProperties({ServerProperties.class})
public class GatewayCommonConfigure {

    private final ServerProperties serverProperties;

    public GatewayCommonConfigure(ServerProperties serverProperties){
        this.serverProperties = serverProperties;
    }

    @Autowired
    private GatewayUrlProperty gatewayUrl;

    /**
     * 通用异常配置，包含json和html类型
     * @param errorAttributes
     * @param resourceProperties
     * @param webProperties
     * @param viewResolvers
     * @param serverCodecConfigurer
     * @param applicationContext
     * @return
     */
    @Bean
    @Order(Ordered.HIGHEST_PRECEDENCE)
    public ShunWebFluxErrorHandler errorWebExceptionHandler(ErrorAttributes errorAttributes,
                                                            org.springframework.boot.autoconfigure.web.ResourceProperties resourceProperties,
                                                            WebProperties webProperties, ObjectProvider<ViewResolver> viewResolvers,
                                                            ServerCodecConfigurer serverCodecConfigurer, ApplicationContext applicationContext) {
        ShunWebFluxErrorHandler jsonWebFluxErrorHandler = new ShunWebFluxErrorHandler(errorAttributes,
                resourceProperties.hasBeenCustomized() ? resourceProperties : webProperties.getResources(),
                this.serverProperties.getError(), applicationContext);
        jsonWebFluxErrorHandler.setViewResolvers(viewResolvers.orderedStream().collect(Collectors.toList()));
        jsonWebFluxErrorHandler.setMessageWriters(serverCodecConfigurer.getWriters());
        jsonWebFluxErrorHandler.setMessageReaders(serverCodecConfigurer.getReaders());
        return jsonWebFluxErrorHandler;
    }

    /**
     * 权限拦截
     * @return
     */
    @Bean
    public SaReactorFilter getSaReactorFilter() {
        log.debug("url配置信息:{}", gatewayUrl);
        return new SaReactorFilter()
                //拦截URL
                .setIncludeList(gatewayUrl.getForbidUrls())
                //通过URL
                .setExcludeList(gatewayUrl.getAllowUrls())
                .setAuth(r -> {
                    //管理端进入
//                    SaRouter.match("/api/**", gatewayUrl.getLoginUrl(), () -> StpUtil.checkLogin());
                    SaRouter.match("/api/**", "/api/auth/**", () -> StpUtil.checkLogin());
                    //手机端/微信端进入
//                    SaRouter.match("/capi/**", gatewayUrl.getLoginUrl(), () -> StpUtil.checkLogin());
                }).setError(e -> {
                    log.info("{}",StpUtil.getTokenInfo());
                    log.warn("SA-token拦截异常信息:{}", e.getMessage());
                    return R.builder().code("10000").msg("用户未登录！");
                });
    }

    /**
     * 处理跨域的问题
     * @return
     */
    @Order(-101)
    @Bean
    public CorsWebFilter crosFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        config.addAllowedOrigin("*");
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource(new PathPatternParser());
        configSource.registerCorsConfiguration("/**", config);
        return new CorsWebFilter(configSource);
    }
}

